package com.xoa.service.nccloud.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xoa.dao.dataSrc.DataSrcMapper;
import com.xoa.dao.ncclound.NCCloudMapper;
import com.xoa.model.nccloud.NCCAccessToken;
import com.xoa.service.nccloud.INCCloudService;
import com.xoa.util.redis.JedisUtil;
import com.xoa.util.redis.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import com.google.gson.Gson;
import com.xoa.util.workapi.CompressUtil;
import com.xoa.util.workapi.Decryption;
import com.xoa.util.workapi.Encryption;
import com.xoa.util.workapi.ResultMessageUtil;
import com.xoa.util.workapi.SHA256Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * NCC接口实现类
 *
 * @author wmf
 * @date 2021年5月19日上午10:53:11
 */
@Service
public class NCCloudServiceImpl implements INCCloudService {


    @Autowired
    private NCCloudMapper ncCloudMapper;
    /**
     * LEVEL0 不压缩、不加密
     */
    public static final String LEVEL0 = "L0";
    /**
     * LEVEL1 只加密、不压缩
     */
    public static final String LEVEL1 = "L1";
    /**
     * LEVEL2 只压缩、不加密
     */
    public static final String LEVEL2 = "L2";
    /**
     * LEVEL3 先压缩、后加密
     */
    public static final String LEVEL3 = "L3";
    /**
     * LEVEL4 先加密、后压缩
     */
    public static final String LEVEL4 = "L4";

    // app_secret
    @Value("${ncc_client_secret}")
    private String client_secret;
    // 公钥
    @Value("${ncc_pubKey}")
    private String pubKey;
    // app_id
    @Value("${ncc_client_id}")
    private String client_id;
    // ncc账套
    @Value("${ncc_busi_center}")
    private String busi_center;
    // 获取token方式：client_credentials、password
    @Value("${ncc_grant_type}")
    private String grant_type;
    // 服务器ip：port
    @Value("${ncc_baseUrl}")
    private String baseUrl;
    // 返回值压缩加密级别
    @Value("${ncc_secret_level}")
    private String secret_level;

    // 重复调用检查
    public static String repeat_check = null;
    // 接口调用业务标识
    public static String busi_id = null;
    // ncc用户名
    private static String username = null;
    // ncc用户名密码
    private static String pwd = null;
    // 请求参数
    private static String requestBody = null;

    @Resource
    private NCCloudMapper cloudMapper;

    @Override
    public String sendApi(String apiUrl, String requestBody) throws Exception {

        long expire = System.currentTimeMillis();
        System.out.println("expire" + expire);
        NCCAccessToken nccAccessToken = cloudMapper.selectToken();
        if (nccAccessToken == null){
            String token = getToken();
            expire += 970000L;
            nccAccessToken = new NCCAccessToken();
            nccAccessToken.setAccessToken(token);
            nccAccessToken.setExpire(expire);
            cloudMapper.insertToken(nccAccessToken);
        }else if (expire > nccAccessToken.getExpire()){
            String token = getToken();
            expire += 970000L;
            nccAccessToken.setAccessToken(getToken());
            nccAccessToken.setExpire(expire);
            cloudMapper.updateToken(nccAccessToken);
        }

        ResultMessageUtil returnData = new Gson().fromJson(nccAccessToken.getAccessToken(),
                ResultMessageUtil.class);
        Map<String, String> data = (Map<String, String>) returnData.getData();
        String access_token = data.get("access_token");
        String security_key = data.get("security_key");
//		String refresh_token = data.get("refresh_token");
//        System.out.println("【ACCESS_TOKEN】:" + access_token);

        // 请求路径
        String url = baseUrl + apiUrl;
        // header 参数
        Map<String, String> headermap = new HashMap<>();
        headermap.put("access_token", access_token);
        headermap.put("client_id", client_id);

        StringBuffer sb = new StringBuffer();
        sb.append(client_id);
        if (StringUtils.isNotBlank(requestBody)) {
            // sb.append(requestBody.replaceAll("\\s*|\t|\r|\n", "").trim());
            sb.append(requestBody);
        }
        sb.append(pubKey);
        String sign = SHA256Util.getSHA256(sb.toString());
        headermap.put("signature", sign);

        if (StringUtils.isNotBlank(busi_id)) {
            headermap.put("busi_id", busi_id);
        }
        if (StringUtils.isNotBlank(repeat_check)) {
            headermap.put("repeat_check", repeat_check);
        }
        headermap.put("ucg_flag", "y");

        String mediaType = "application/json;charset=utf-8";

//        System.out.println("【requestBody】:" + requestBody);
        // 表体数据json
        // 根据安全级别选择加密或压缩请求表体参数
        String json = dealRequestBody(requestBody, security_key, secret_level);
//        System.out.println("【json】:" + json);
        // 返回值
        String result = doPost(url, null, mediaType, headermap, json);
        System.out.println("【RESULT】:" + result);
        //返回结果错误不是加密压缩的，进行异常抛出
        String result2DecryptAndDecompress=null;
        try {
            result2DecryptAndDecompress = dealResponseBody(result,
                    security_key, secret_level);
        }catch (Exception e){
           throw new RuntimeException(result);
        }
        System.out.println("result解密:" + result2DecryptAndDecompress);
        return result2DecryptAndDecompress;
    }

    /**
     * 发送post请求
     *
     * @param baseUrl
     * @param paramMap
     * @param mediaType
     * @param headers
     * @param json
     * @return
     */
    private String doPost(String baseUrl, Map<String, String> paramMap, String mediaType, Map<String, String> headers, String json) {
        HttpURLConnection urlConnection = null;
        InputStream in = null;
        OutputStream out = null;
        BufferedReader bufferedReader = null;
        String result = null;
        try {
            StringBuffer sb = new StringBuffer();
            sb.append(baseUrl);
            if (paramMap != null) {
                sb.append("?");
                for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    sb.append(key + "=" + value).append("&");
                }
                baseUrl = sb.toString()
                        .substring(0, sb.toString().length() - 1);
            }

            URL urlObj = new URL(baseUrl);
            urlConnection = (HttpURLConnection) urlObj.openConnection();


            urlConnection.setConnectTimeout(5*1000);

            urlConnection.setConnectTimeout(50000);


            urlConnection.setConnectTimeout(50000);

            urlConnection.setRequestMethod("POST");
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setUseCaches(false);
            urlConnection.addRequestProperty("content-type", mediaType);
            if (headers != null) {
                for (String key : headers.keySet()) {
                    urlConnection.addRequestProperty(key, headers.get(key));
                }
            }
            out = urlConnection.getOutputStream();
            out.write(json.getBytes("utf-8"));
            out.flush();
            int resCode = urlConnection.getResponseCode();
            if (resCode == HttpURLConnection.HTTP_OK
                    || resCode == HttpURLConnection.HTTP_CREATED
                    || resCode == HttpURLConnection.HTTP_ACCEPTED) {
                in = urlConnection.getInputStream();
            } else {
                in = urlConnection.getErrorStream();
            }
            bufferedReader = new BufferedReader(new InputStreamReader(in,
                    "utf-8"));
            StringBuffer temp = new StringBuffer();
            String line = bufferedReader.readLine();
            while (line != null) {
                temp.append(line).append("\r\n");
                line = bufferedReader.readLine();
            }
            String ecod = urlConnection.getContentEncoding();
            if (ecod == null) {
                ecod = Charset.forName("utf-8").name();
            }
            result = new String(temp.toString().getBytes("utf-8"), ecod);
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (null != bufferedReader) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            urlConnection.disconnect();
        }
        return result;
    }

    /**
     * 获取access_token
     *
     * @return
     * @throws Exception
     */
    private String getToken() throws Exception {
        // 客户端模式
        String token = getTokenByClient();
        if ("password".equals(grant_type)) {
            // 密码模式
            token = getTokenByPWD();
        }
        return token;
    }

    /**
     * 客户端模式获取token
     *
     * @return
     * @throws Exception
     */
    private String getTokenByClient() throws Exception {
        Map<String, String> paramMap = new HashMap<String, String>();
        // 密码模式认证
        paramMap.put("grant_type", "client_credentials");
        // 第三方应用id
        paramMap.put("client_id", client_id);
        // 第三方应用secret 公钥加密
        paramMap.put("client_secret", URLEncoder.encode(
                Encryption.pubEncrypt(pubKey, client_secret), "utf-8"));
        // 账套编码
        paramMap.put("biz_center", busi_center);
        // // TODO 传递数据源和ncc登录用户
        // paramMap.put("dsname", "TM_0614");
        // paramMap.put("usercode", "1");

        // 签名
        String sign = SHA256Util.getSHA256(client_id + client_secret + pubKey);
        paramMap.put("signature", sign);

        String url = baseUrl + "/nccloud/opm/accesstoken";
        String mediaType = "application/x-www-form-urlencoded";
        String token = doPost(url, paramMap, mediaType, null, "");
        return token;
    }

    /**
     * 密码模式获取token
     *
     * @return
     * @throws Exception
     */
    private String getTokenByPWD() throws Exception {
        Map<String, String> paramMap = new HashMap<String, String>();
        // 密码模式认证
        paramMap.put("grant_type", "password");
        // 第三方应用id
        paramMap.put("client_id", client_id);
        // 第三方应用secret 公钥加密
        paramMap.put("client_secret", URLEncoder.encode(
                Encryption.pubEncrypt(pubKey, client_secret), "utf-8"));
        // ncc用户名
        paramMap.put("username", username);
        // 密码 公钥加密
        paramMap.put("password",
                URLEncoder.encode(Encryption.pubEncrypt(pubKey, pwd), "utf-8"));
        // 账套编码
        paramMap.put("biz_center", busi_center);
        // 签名
        String sign = SHA256Util.getSHA256(client_id + client_secret + username
                + pwd + pubKey);
        paramMap.put("signature", sign);

        String url = baseUrl + "/nccloud/opm/accesstoken";
        String mediaType = "application/x-www-form-urlencoded";
        String token = doPost(url, paramMap, mediaType, null, "");
        return token;
    }

    /**
     * 返回值进行过加密和压缩，对返回值进行解压和解密
     *
     * @param source
     * @param security_key
     * @param level
     * @return
     * @throws Exception
     */
    @Override
    public String dealResponseBody(String source, String security_key,
                                           String level) throws Exception {
        String result = null;

        if (StringUtils.isEmpty(level) || LEVEL0.equals(level)) {
            result = source;
        } else if (LEVEL1.equals(level)) {
            result = Decryption.symDecrypt(security_key, source);
        } else if (LEVEL2.equals(level)) {
            result = CompressUtil.gzipDecompress(source);
        } else if (LEVEL3.equals(level)) {
            result = CompressUtil.gzipDecompress(Decryption.symDecrypt(
                    security_key, source));
        } else if (LEVEL4.equals(level)) {
            result = Decryption.symDecrypt(security_key,
                    CompressUtil.gzipDecompress(source));
        } else {
            throw new Exception("无效的安全等级");
        }

        return result;
    }

    // 根据安全级别设置，表体是否加密或压缩
    @Override
    public String dealRequestBody(String source, String security_key,
                                          String level) throws Exception {
        String result = null;
        if (StringUtils.isEmpty(level) || LEVEL0.equals(level)) {
            result = source;
        } else if (LEVEL1.equals(level)) {

            result = Encryption.symEncrypt(security_key, source);
            System.out.println("1成功"+result);
        } else if (LEVEL2.equals(level)) {
            result = CompressUtil.gzipCompress(source);
            System.out.println("2成功"+result);
        } else if (LEVEL3.equals(level)) {
            result = Encryption.symEncrypt(security_key,
                    CompressUtil.gzipCompress(source));
            System.out.println("3成功"+result);
        } else if (LEVEL4.equals(level)) {
            result = CompressUtil.gzipCompress(Encryption.symEncrypt(
                    security_key, source));
            System.out.println("4成功"+result);
        } else {
            throw new Exception("无效的安全等级");
        }

        return result;
    }
    //公共查询表方法返回全部信息，传入表名
    @Override
    public List<Map<String, Object>> selectAll(Map map) {
        return ncCloudMapper.selectTableAll(map);
    }
}
